package com.z.redis.command.impl.string;

import com.z.redis.RedisCore;
import com.z.redis.command.CommandType;
import com.z.redis.command.WriteCommand;
import com.z.redis.datatype.BytesWrapper;
import com.z.redis.datatype.RedisString;
import com.z.redis.resp.BulkString;
import com.z.redis.resp.Resp;
import com.z.redis.resp.SimpleString;
import io.netty.channel.ChannelHandlerContext;

/**
 * SET key value [EX seconds] [PX milliseconds] [NX|XX]
 * 设置键值对
 */
public class Set implements WriteCommand {
    private BytesWrapper key; // 存储键
    private BytesWrapper value; // 存储值
    private long timeout = -1; // 过期时间
    private boolean notExistSet = false; // NX标志 键不存在时设置
    private boolean existSet = false; // XX标志 键存在时设置

    @Override
    public CommandType type(){
        return CommandType.set;
    }

    /**
     * SET key value [EX seconds] [PX milliseconds] [NX|XX]
     * 处理EX（秒级过期） PX（毫秒级过期） NX（键不存在时设置） XX（键存在时设置）
     * @param array 命令内容
     */
    @Override
    public void setContent(Resp[] array){
        key =((BulkString) array[1]).getContent(); // 获取键
        value = ((BulkString) array[2]).getContent(); // 获取值
        int index=3;
        while(index<array.length){
            String string = ((BulkString) array[index]).getContent().toUTF8String();
            index++;
            if(string.startsWith("EX")){
                String seconds = ((BulkString) array[index]).getContent().toUTF8String();
                timeout = Long.parseLong(seconds)*1000; // 秒转毫秒
            }else if(string.startsWith("PX")){
                String seconds = ((BulkString) array[index]).getContent().toUTF8String();
                timeout = Long.parseLong(seconds); // 毫秒
            }else if(string.startsWith("NX")){
                notExistSet = true;
            }else if(string.startsWith("XX")){
                existSet = true;
            }
        }
    }

    @Override
    public void handle(ChannelHandlerContext ctx, RedisCore redisCore){
        // NX条件检查 键存在则返回null
        if(notExistSet && redisCore.exist(key)){
            ctx.writeAndFlush(BulkString.NullBulkString);
        }
        // XX条件检查 键不存在则返回null
        else if(existSet && !redisCore.exist(key)) {
            ctx.writeAndFlush(BulkString.NullBulkString);
        }else{
            if(timeout != -1){
                timeout += System.currentTimeMillis(); // 转成绝对时间数
            }
            RedisString stringData = new RedisString(value);
            stringData.setTimeout(timeout);
            redisCore.put(key, stringData);
            ctx.writeAndFlush(SimpleString.OK);
        }
    }

    @Override
    public void handle(RedisCore redisCore){
        if(notExistSet && redisCore.exist(key)){
        }
        else if(existSet && !redisCore.exist(key)) {
        }else{
            if(timeout != -1){
                timeout += System.currentTimeMillis(); // 转成绝对时间数
            }
            RedisString stringData = new RedisString(value);
            stringData.setTimeout(timeout);
            redisCore.put(key, stringData);
        }
    }
}
